use crate::exchange::lib::{CONFIG, TICKER, Ticker, callback};
use crate::utils::{READ_BUFFER_SIZE, WRITE_BUFFER_SIZE, parse_frame, start_ws};
use sonic_rs::JsonValueTrait;
use std::sync::Arc;
use tokio::io::{AsyncWriteExt, BufReader, BufWriter};

pub async fn ws(symbols: Arc<Vec<String>>) {
    let params = symbols
        .iter()
        .map(|x| format!("{}@bookTicker", x.to_lowercase()))
        .collect::<Vec<String>>()
        .join("/");

    let params = format!("streams={}", params);

    loop {
        let (rx, tx) = start_ws(
            "fstream.binance.com",
            Some("/stream"),
            Some(params.as_str()),
            CONFIG.proxy.as_str(),
        )
        .await;

        let mut buf_reader = BufReader::with_capacity(READ_BUFFER_SIZE, rx);
        let mut buf_writer = BufWriter::with_capacity(WRITE_BUFFER_SIZE, tx);

        loop {
            match parse_frame(&mut buf_reader).await {
                Ok((opcode, payload)) => {
                    match opcode {
                        0x1 => {
                            let obj = unsafe {
                                sonic_rs::get_from_slice_unchecked(&payload, &["data"]).unwrap()
                            };

                            let timestamp = obj.get("T").unwrap().as_i64().unwrap();

                            let bid = obj
                                .get("b")
                                .unwrap()
                                .as_str()
                                .unwrap()
                                .parse::<f64>()
                                .unwrap();
                            let bid_amount = obj
                                .get("B")
                                .unwrap()
                                .as_str()
                                .unwrap()
                                .parse::<f64>()
                                .unwrap();

                            let ask = obj
                                .get("a")
                                .unwrap()
                                .as_str()
                                .unwrap()
                                .parse::<f64>()
                                .unwrap();
                            let ask_amount = obj
                                .get("A")
                                .unwrap()
                                .as_str()
                                .unwrap()
                                .parse::<f64>()
                                .unwrap();

                            let symbol = obj.get("s").unwrap().as_str().unwrap().to_string();

                            let mut value = TICKER
                                .entry(symbol.clone())
                                .or_insert_with(|| Ticker::default());

                            value.main = (bid, ask);
                            value.main_timestamp = timestamp;
                            value.main_bid_amount = bid_amount;
                            value.main_ask_amount = ask_amount;

                            drop(value);

                            // 采集行情
                            callback(symbol).await;
                        }
                        0x2 => {
                            // 二进制帧
                            println!("收到二进制数据，长度: {}", payload.len());
                        }
                        0x8 => {
                            // 关闭帧
                            println!("连接关闭");
                            break;
                        }
                        0x9 => {
                            // println!("收到ping帧");
                            let pong_frame = vec![
                                0x8A, // FIN=1, OPCODE=0xA (Pong)
                                0x00, // 长度=0 (空帧)
                            ];

                            buf_writer.write_all(&pong_frame).await.unwrap();
                            buf_writer.flush().await.unwrap();
                        }
                        0xa => {
                            println!("收到pong帧");
                        }
                        _ => {
                            println!("收到其他帧，opcode: {opcode}");
                        }
                    }
                }
                Err(e) => {
                    println!("读取错误: {e}");
                    tokio::time::sleep(std::time::Duration::from_secs(1)).await;
                    break;
                }
            }
        }
    }
}
